extern crate fejpsl_contract;
use fejpsl_contract::user::{User,UserKey};
use md5;
use rand;
use uuid::Uuid;
use chrono::prelude::*;
use self::fejpsl_contract::user::UserKeyData;

/// all letters
const ALL_LETTERS: &str = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
/// 安全密鑰
const SECRET_KEYS: &str = "!s@w4$qS%^(_123-=0Xha9452sLW^%sfa9)\\";

pub async fn get_user_by_id(id:&String) -> Option<User> {
    let client = super::db::connect().await.unwrap();
    let rows = &client.query("SELECT id,user_uuid,user_name,nice_name,real_name,sex,\
        birth_day,phone,avatar_text,token,user_id,email,credit_score,area,address,is_explicit,copper_cash,\
        gold_ingot,level_score FROM t_user where id::text=$1", &[&id]).await.unwrap();
    let row = rows.get(0).unwrap();
    let user = User {
        user_uuid: row.get(1),
        user_name:  row.get(2),
        nice_name:  row.get(3),
        real_name: row.get(4),
        sex:   row.get(5),
        birth_day: row.get(6),
        phone:  row.get(7),
        avatar_text:  row.get(8),
        token:row.get(9),
        user_id:row.get(10),
         email:row.get(11),
         credit_score:row.get(12),
         area:row.get(13),
         address:row.get(14),
        is_explicit:row.get(15),
        copper_cash:row.get(16),
        gold_ingot:row.get(17),
        level_score:row.get(18),
    };
    return Some(user);
}
pub async fn get_user_by_uuid(user_uuid:&String) -> Option<User> {
    let client = super::db::connect().await.unwrap();
    let rows = &client.query("SELECT id,user_uuid,user_name,nice_name,real_name,sex,\
        birth_day,phone,avatar_text,token,user_id,email,credit_score,area,address,is_explicit,copper_cash,\
        gold_ingot,level_score FROM t_user where user_uuid=$1", &[&user_uuid]).await.unwrap();
    let row = rows.get(0).unwrap();
    let mut m_real_name=String::from("");
    let tmp_str: Option<String> = row.get(4);
    if let Some(_i) = tmp_str {m_real_name= row.get(4); }else{ m_real_name=String::from("") }
    let mut m_birth_day=String::from("");
    let tmp_str: Option<String> = row.get(6);
    if let Some(_i) = tmp_str {m_birth_day= row.get(6); }else{ m_birth_day=String::from("") }
    let mut m_phone=String::from("");
    let tmp_str: Option<String> = row.get(7);
    if let Some(_i) = tmp_str {m_phone= row.get(7); }else{ m_phone=String::from("") }
    let mut m_avatar_text=String::from("");
    let tmp_str: Option<String> = row.get(8);
    if let Some(_i) = tmp_str {m_avatar_text= row.get(8); }else{ m_avatar_text=String::from("") }
    let mut m_email=String::from("");
    let tmp_str: Option<String> = row.get(11);
    if let Some(_i) = tmp_str {m_email= row.get(11); }else{ m_email=String::from("") }
    let mut m_area=String::from("");
    let tmp_str: Option<String> = row.get(13);
    if let Some(_i) = tmp_str {m_area= row.get(13); }else{ m_area=String::from("") }
    let mut m_address=String::from("");
    let tmp_str: Option<String> = row.get(14);
    if let Some(_i) = tmp_str {m_address= row.get(14); }else{ m_address=String::from("") }
    let mut m_user_name=String::from("");
    let tmp_str: Option<String> = row.get(2);
    if let Some(_i) = tmp_str {m_user_name= row.get(2); }else{ m_user_name=String::from("") }
    let user = User {
        user_uuid: row.get(1),
        user_name: row.get(2),
        nice_name: row.get(3),
        real_name: m_real_name,
        sex: row.get(5),
        birth_day: m_birth_day,
        phone: m_phone,
        avatar_text: m_avatar_text,
        token: row.get(9),
        user_id: row.get(10),
        email: m_email,
        credit_score: row.get(12),
        area: m_area,
        address:m_address,
        is_explicit: row.get(15),
        copper_cash:row.get(16),
        gold_ingot:row.get(17),
        level_score:row.get(18),
    };
    let m_content="用户".to_string()+&m_user_name+"登录了火鸟教育App";
    let local: DateTime<Local> = Local::now(); // 本地时间
    let m_create_time = local.format("%Y-%m-%d %H:%M:%S%.3f").to_string();
    let mut m_real_name=String::from("");
    let tmp_str: Option<String> = row.get(4);
    if let Some(_i) = tmp_str {m_real_name= row.get(4); }else{ m_real_name=String::from("") }
    let _row = client.query("INSERT INTO t_user_event_log (user_uuid,user_name,real_name,content,create_time) \
            VALUES($1,$2,$3,$4,$5)",
                            &[&user_uuid,&m_user_name,&m_real_name,&m_content,&m_create_time]).await.unwrap();

    return Some(user);
}

pub async fn user_register(user_name:&String,password:&String) -> Option<User> {
    let client = super::db::connect().await.unwrap();
    let rows = &client.query("SELECT id,user_name FROM t_user where user_name::text=$1", &[&user_name]).await.unwrap();
    let count  = rows.len();
    if count>0 {
        let user = User {
            user_uuid:  String::from(""),
            user_name:  String::from(""),
            nice_name: String::from(""),
            real_name:  String::from(""),
            sex: 0,
            birth_day: String::from(""),
            phone: String::from(""),
            avatar_text: String::from(""),
            token:  String::from(""),
            user_id:  String::from(""),
            email: String::from(""),
            credit_score: 0,
            area: String::from(""),
            address: String::from(""),
            is_explicit:0,
            copper_cash:0,
            gold_ingot:0,
            level_score:0,
        };
        println!("{:?}","此用户名已被注册！");
        return Some(user);
    };
    let user_uuid = Uuid::new_v4().to_string();
    //let user_uuid="55bad52c-cdf7-4321-87b8-e37d958b24cf";
    let origin_password = password;
    let token = rand_str(32);
    let encrypt_password = get_password(origin_password, token.as_str());
    println!("{:?}",format!("username: {}\nsecret = {}\npassword = {}", user_name, token, encrypt_password));
    let local: DateTime<Local> = Local::now(); // 本地时间
    println!(
        " date 精确到毫秒 ({:?})",
        local.format("%Y-%m-%d %H:%M:%S%.3f").to_string()
    );
    let create_time=local.format("%Y-%m-%d %H:%M:%S%.3f").to_string();
    let rows = &client.query("SELECT max(cast(user_id as integer))::character varying FROM public.t_user where user_id is not null ", &[]).await.unwrap();
    let count  = rows.len();
    let mut init_user_id:i64=10000000;
    if count>0 {
        let row = rows.get(0).unwrap();
        let max_user_id:&str=row.get(0);
        init_user_id=max_user_id.parse::<i64>().unwrap();
        init_user_id=init_user_id+1;
    };
    let new_user_id=init_user_id.to_string();
    let user_level=999;
    let role=1;
    let status=1;
    let deleted=false;
    let credit_score=100;
    let is_explicit=1;
    let sex=1;
    let copper_cash:i64=5000;
    let gold_ingot:i64=0;
    let level_score:i64=0;
    let _row = client.query("INSERT INTO t_user (user_name,password,nice_name,token,user_uuid,user_level,role,status,create_time,modify_time,\
        deleted,credit_score,user_id,is_explicit,sex,copper_cash,gold_ingot,level_score) VALUES($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18)",
                            &[&user_name,&encrypt_password,&user_name,&token,&user_uuid,&user_level,&role,&status,&create_time,&create_time,
                                &deleted,&credit_score,&new_user_id,&is_explicit,&sex,&copper_cash,&gold_ingot,&level_score]).await.unwrap();
    let user = User {
        user_uuid:user_uuid.to_string(),
        user_name:user_name.to_string(),
         nice_name:user_name.to_string(),
         real_name:String::from(""),
         sex:1,
         birth_day:String::from(""),
         phone:String::from(""),
         avatar_text:String::from(""),
         token:token.to_string(),
         user_id:init_user_id.to_string(),
         email:String::from(""),
         credit_score:100,
         area:String::from(""),
         address:String::from(""),
        is_explicit:1,
        copper_cash:5000,
        gold_ingot:0,
        level_score:0,
    };
    let m_content="欢迎".to_string()+&user_name+"注册了火鸟教育App";
    let local: DateTime<Local> = Local::now(); // 本地时间
    let m_create_time = local.format("%Y-%m-%d %H:%M:%S%.3f").to_string();
    let m_real_name=String::from("");
    let _row = client.query("INSERT INTO t_user_event_log (user_uuid,user_name,real_name,content,create_time) \
            VALUES($1,$2,$3,$4,$5)",
                            &[&user_uuid,&user_name,&m_real_name,&m_content,&m_create_time]).await.unwrap();

    return Some(user);
}

pub async fn user_login(user_name:&String,password:&String) -> Option<User> {
    let client = super::db::connect().await.unwrap();
    let rows = &client.query("SELECT id,user_uuid,user_name,nice_name,real_name,sex,\
        birth_day,phone,avatar_text,token,user_id,email,credit_score,area,address,is_explicit,password,\
        copper_cash,gold_ingot,level_score FROM t_user \
        where user_name::text=$1", &[&user_name]).await.unwrap();
    let count  = rows.len();
    if count>0 {
        let row = rows.get(0).unwrap();
        let token:&str = row.get(9);
        let origin_password = password;
        let encrypt_password = get_password(origin_password, token.to_string().as_str());
        let password:&str = row.get(16);
        if encrypt_password == password.to_string() {  //对比加密之后的密码是否一致
            let mut m_real_name=String::from("");
            let tmp_str: Option<String> = row.get(4);
            if let Some(_i) = tmp_str {m_real_name= row.get(4); }else{ m_real_name=String::from("") }
            let mut m_birth_day=String::from("");
            let tmp_str: Option<String> = row.get(6);
            if let Some(_i) = tmp_str {m_birth_day= row.get(6); }else{ m_birth_day=String::from("") }
            let mut m_phone=String::from("");
            let tmp_str: Option<String> = row.get(7);
            if let Some(_i) = tmp_str {m_phone= row.get(7); }else{ m_phone=String::from("") }
            let mut m_avatar_text=String::from("");
            let tmp_str: Option<String> = row.get(8);
            if let Some(_i) = tmp_str {m_avatar_text= row.get(8); }else{ m_avatar_text=String::from("") }
            let mut m_email=String::from("");
            let tmp_str: Option<String> = row.get(11);
            if let Some(_i) = tmp_str {m_email= row.get(11); }else{ m_email=String::from("") }
            let mut m_area=String::from("");
            let tmp_str: Option<String> = row.get(13);
            if let Some(_i) = tmp_str {m_area= row.get(13); }else{ m_area=String::from("") }
            let mut m_address=String::from("");
            let tmp_str: Option<String> = row.get(14);
            if let Some(_i) = tmp_str {m_address= row.get(14); }else{ m_address=String::from("") }
            let mut m_user_uuid=String::from("");
            let tmp_str: Option<String> = row.get(1);
            if let Some(_i) = tmp_str {m_user_uuid= row.get(1); }else{ m_user_uuid=String::from("") }
            let user = User {
                user_uuid: row.get(1),
                user_name: row.get(2),
                nice_name: row.get(3),
                real_name: m_real_name,
                sex: row.get(5),
                birth_day: m_birth_day,
                phone: m_phone,
                avatar_text: m_avatar_text,
                token: row.get(9),
                user_id: row.get(10),
                email: m_email,
                credit_score: row.get(12),
                area: m_area,
                address:m_address,
                is_explicit: row.get(15),
                copper_cash:row.get(17),
                gold_ingot:row.get(18),
                level_score:row.get(19),
            };

            /*let local: DateTime<Local> = Local::now(); // 本地时间
            println!(
                " date 精确到毫秒 ({:?})",
                local.format("%Y-%m-%d %H:%M:%S%.3f").to_string()
            );
            let last_active_time = local.format("%Y-%m-%d %H:%M:%S%.3f").to_string();
            let mut login_count :i32= row.get(17);
            login_count=login_count+1;
            let uid:i32=row.get(0);
            let _row = client.query("UPDATE t_user set last_active_time=$2,login_count=$3 where id=$1",
                                    &[&uid,&last_active_time,&login_count]).await.unwrap();
*/
            let m_content="欢迎".to_string()+&user_name+"登录了火鸟教育App";
            let local: DateTime<Local> = Local::now(); // 本地时间
            let m_create_time = local.format("%Y-%m-%d %H:%M:%S%.3f").to_string();
            let mut m_real_name=String::from("");
            let tmp_str: Option<String> = row.get(4);
            if let Some(_i) = tmp_str {m_real_name= row.get(4); }else{ m_real_name=String::from("") }
            let _row = client.query("INSERT INTO t_user_event_log (user_uuid,user_name,real_name,content,create_time) \
            VALUES($1,$2,$3,$4,$5)",
                                    &[&m_user_uuid,&user_name,&m_real_name,&m_content,&m_create_time]).await.unwrap();
            return Some(user);
        }
    }

    let user = User {
        user_uuid:  String::from(""),
        user_name:  String::from(""),
        nice_name: String::from(""),
        real_name:  String::from(""),
        sex: 0,
        birth_day: String::from(""),
        phone: String::from(""),
        avatar_text: String::from(""),
        token:  String::from(""),
        user_id:  String::from(""),
        email: String::from(""),
        credit_score: 0,
        area: String::from(""),
        address: String::from(""),
        is_explicit:0,
        copper_cash:0,
        gold_ingot:0,
        level_score:0,
    };
    println!("{:?}",format!("***用户名称或密码错误->username: {}\n password = {}", user_name,password));
    //return response::error("用户名称或密码错误");
    return Some(user);
}

pub async fn update_user_by_id(id:&i32,user_name:&String,real_name:&String,age:&i32,sex:&i32,birth_day:&String,phone:&String) -> Option<bool> {
    let client = super::db::connect().await.unwrap();
    let _row = client.query("UPDATE t_user set user_name::text=$2,real_name::text=$3,age::text=$4,sex::text=$5,birth_day::text=$6,phone::text=$7 where id::text=$1",
                            &[&id,&user_name,&real_name,&age,&sex,&birth_day,&phone]).await.unwrap();
    return Some(true);
}
pub async fn update_user_avatar(user_uuid:&String,avatar_text:&String) -> Option<UserKeyData> {
    let client = super::db::connect().await.unwrap();
    let _row = client.query("UPDATE t_user set avatar_text::text=$2 where user_uuid=$1",
                            &[&user_uuid,&avatar_text]).await.unwrap();
    let user_key=UserKey{
        key_string:String::from(avatar_text),
        key_int:0,
    };
    let user_key_data=UserKeyData{
        data: Some(user_key),
        error_code:0,
        error_msg:"success".to_string(),
    };
    return Some(user_key_data);
}
pub async fn update_user_phone(user_uuid:&String,phone:&String) -> Option<UserKeyData> {
    let client = super::db::connect().await.unwrap();
    let _row = client.query("UPDATE t_user set phone=$2 where user_uuid=$1",
                            &[&user_uuid,&phone]).await.unwrap();
    let user_key=UserKey{
        key_string:String::from(phone),
        key_int:0,
    };
    let user_key_data=UserKeyData{
        data:Some(user_key),
        error_code:0,
        error_msg:"success".to_string(),
    };
    return Some(user_key_data);
}
pub async fn update_user_email(user_uuid:&String,email:&String) -> Option<UserKeyData> {
    let client = super::db::connect().await.unwrap();
    let _row = client.query("UPDATE t_user set email=$2 where user_uuid=$1",
                            &[&user_uuid,&email]).await.unwrap();
    let user_key=UserKey{
        key_string:String::from(email),
        key_int:0,
    };
    let user_key_data=UserKeyData{
        data:Some(user_key),
        error_code:0,
        error_msg:"success".to_string(),
    };
    return Some(user_key_data);
}
pub async fn update_user_birthday(user_uuid:&String,birthday:&String) -> Option<UserKeyData> {
    let client = super::db::connect().await.unwrap();
    let _row = client.query("UPDATE t_user set birth_day=$2 where user_uuid=$1",
                            &[&user_uuid,&birthday]).await.unwrap();
    let user_key=UserKey{
        key_string:String::from(birthday),
        key_int:0,
    };
    let user_key_data=UserKeyData{
        data:Some(user_key),
        error_code:0,
        error_msg:"success".to_string(),
    };
    return Some(user_key_data);
}
pub async fn update_user_sex(user_uuid:&String,sex:&i32) -> Option<UserKeyData> {
    let client = super::db::connect().await.unwrap();
    let _row = client.query("UPDATE t_user set sex=$2 where user_uuid=$1",
                            &[&user_uuid,&sex]).await.unwrap();
    let user_key=UserKey{
        key_string:String::from(""),
        key_int:*sex,
    };
    let user_key_data=UserKeyData{
        data:Some(user_key),
        error_code:0,
        error_msg:"success".to_string(),
    };
    return Some(user_key_data);
}
pub async fn update_user_real_name(user_uuid:&String,real_name:&String) -> Option<UserKeyData> {
    let client = super::db::connect().await.unwrap();
    let _row = client.query("UPDATE t_user set real_name=$2 where user_uuid=$1",
                            &[&user_uuid,&real_name]).await.unwrap();
    let user_key=UserKey{
        key_string:real_name.to_owned(),
        key_int:0,
    };
    let user_key_data=UserKeyData{
        data:Some(user_key),
        error_code:0,
        error_msg:"success".to_string(),
    };
    return Some(user_key_data);
}
pub async fn update_user_nice_name(user_uuid:&String,nice_name:&String) -> Option<UserKeyData> {
    let client = super::db::connect().await.unwrap();
    let _row = client.query("UPDATE t_user set nice_name=$2 where user_uuid=$1",
                            &[&user_uuid,&nice_name]).await.unwrap();
    let user_key=UserKey{
        key_string:nice_name.to_owned(),
        key_int:0,
    };
    let user_key_data=UserKeyData{
        data:Some(user_key),
        error_code:0,
        error_msg:"success".to_string(),
    };
    return Some(user_key_data);
}
pub async fn update_user_is_explicit(user_uuid:&String,is_explicit:&i32) -> Option<UserKeyData> {
    let client = super::db::connect().await.unwrap();
    let _row = client.query("UPDATE t_user set is_explicit=$2 where user_uuid=$1",
                            &[&user_uuid,&is_explicit]).await.unwrap();
    let user_key=UserKey{
        key_string:String::from(""),
        key_int: *is_explicit,
    };
    let user_key_data=UserKeyData{
        data:Some(user_key),
        error_code:0,
        error_msg:"success".to_string(),
    };
    return Some(user_key_data);
}
pub async fn update_user_area(user_uuid:&String,area:&String) -> Option<UserKeyData> {
    let client = super::db::connect().await.unwrap();
    let _row = client.query("UPDATE t_user set area=$2 where user_uuid=$1",
                            &[&user_uuid,&area]).await.unwrap();
    let user_key=UserKey{
        key_string:area.to_owned(),
        key_int:0,
    };
    let user_key_data=UserKeyData{
        data:Some(user_key),
        error_code:0,
        error_msg:"success".to_string(),
    };
    return Some(user_key_data);
}
/// random string
pub fn rand_str(length: usize) -> String {
    let mut target = String::from("");
    let chars :Vec<char> = ALL_LETTERS.chars().collect();
    for _ in 0..length {
        let rand_num = rand::random::<usize>();
        target.push(chars[rand_num % 62]);
    }
    target
}
/// md5
#[inline]
pub fn md5_str(content: &str) -> String {
    let encrypt = md5::compute(content);
    format!("{:x}", encrypt)
}

/// 生成密碼
#[inline]
pub fn get_password(real_password: &str, secret: &str) -> String {
    let origin = format!("{}-{}-{}", real_password, SECRET_KEYS, secret);
    md5_str(origin.as_str())
}
